﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using GeoSketch2.Core;

namespace GeoSketch2.Archaeo
{
    /// <summary>
    /// The line distances tools
    /// This tool is used to construct a point when 2 orthogonal distance from 2 lines are known
    /// the 2 lines are cloned with an offset and their intersection is the constructed point
    /// </summary>
    public class TLineDistances: BaseArchaeoTool
    {
        #region Fields
        Line2D64D Line1, Line2;
        Point2D64D SidePoint1, SidePoint2;
        Line2D64D ShiftedLine1, ShiftedLine2;
        double Offset1, Offset2; 
        #endregion

        #region Constructor
        /// <summary>
        /// The tool to construct a point from 2 orthogonal distances from 2 lines
        /// </summary>
        /// <param name="Viewport">The viewport the tool with act on</param>
        public TLineDistances(Viewport Viewport)
            : base(Viewport,"Lines distances")
        {
        } 
        #endregion

        #region Inputs
        /// <summary>
        /// The method called when the mouse button is down
        /// </summary>
        public override void MouseDown(MouseEventArgs MouseArgs)
        {
            ExternalPointSent(Viewport.Object2ImageTransformation.InverseTransform(MouseArgs.Location));
        }

        /// <summary>
        /// The method called when a point in object coordinates is sent to the tool
        /// </summary>
        public override void ExternalPointSent(Point2D64D Point)
        {
            if (Line1 == null && SidePoint1 == null && Offset1 == 0)
            {
                Line1 = GetLine(Point);
                SendMessage("Click the side of the line where the distance is measured");
                RefreshViewport();
            }
            else if (Line1 != null && SidePoint1 == null && Offset1 == 0)
            {
                SidePoint1 = Point;
                SendMessage("Enter the distance to the line");
                ShowTextInput();
            }
            else if (Line2 == null && SidePoint2 == null && Offset2 == 0)
            {
                Line2 = GetLine(Point);
                SendMessage("Click the side of the line where the distance is measured");
                RefreshViewport();
            }
            else if (Line2 != null && SidePoint2 == null && Offset2 == 0)
            {
                SidePoint2 = Point;
                SendMessage("Enter the distance to the line");
                ShowTextInput();
            }
            else if (Offset1 > 0 && Offset2 > 0)
            {
                Point2D NewPoint = new Point2D(
                ShiftedLine1.LinesIntersection(ShiftedLine2),
                Viewport.CurrentLayer,
                null,
                Viewport.CurrentColor,
                Viewport.CurrentLineType);
                Viewport.GeoObjects.Add(NewPoint);
                NewPoint.Draw(Viewport);

                Line1=null;
                Line2 = null;
                ShiftedLine1 = null;
                ShiftedLine2 = null;
                SidePoint1 = null;
                SidePoint2 = null;
                Offset1 = 0;
                Offset2 = 0;
                SendMessage("Click the first line");
                RefreshViewport();
            }
        }

        /// <summary>
        /// The method called when a text is sent to the tool
        /// </summary>
        public override void TextEntry(string Text)
        {
            if (Line1 != null && SidePoint1 != null && Offset1 == 0)
            {
                Offset1 = Convert.ToDouble(Text.Replace(',', '.'), Core.Vars.Setup.GeoSketch.NumberFormat);
                SendMessage("Click the second line");

                Point2D64D OffsetVector1;
                if (Line1.LeftNormalVector.DotProduct(SidePoint1 - Line1.Point1) > 0)
                {
                    OffsetVector1 = Line1.LeftNormalVector;
                }
                else
                {
                    OffsetVector1 = Line1.RightNormalVector;
                }
                ShiftedLine1 = Line1.GetTranslatedLine(OffsetVector1 * Offset1);
                RefreshViewport();
            }
            else if (Line2 != null && SidePoint2 != null && Offset2 == 0)
            {
                Offset2 = Convert.ToDouble(Text.Replace(',', '.'), Core.Vars.Setup.GeoSketch.NumberFormat);
                SendMessage("Click to validate the intersection, unselect tool to cancel");

                Point2D64D OffsetVector2;

                if (Line2.LeftNormalVector.DotProduct(SidePoint2 - Line2.Point1) > 0)
                {
                    OffsetVector2 = Line2.LeftNormalVector;
                }
                else
                {
                    OffsetVector2 = Line2.RightNormalVector;
                }

                ShiftedLine2 = Line2.GetTranslatedLine(OffsetVector2 * Offset2);
                RefreshViewport();
            }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Gets the nearest line to a clic
        /// </summary>
        private Line2D64D GetLine(Point2D64D Point)
        {
            double is_near_distance_object_coordinates = Viewport.Object2ImageTransformation.InverseTransform(Core.Vars.Setup.Tools.TSelection.IsNearDistance);
            Point2D64D clic_object_coordinates = Point;
            Line2D64D LineFound = null;

            foreach (BaseDrawableObject obj in Viewport.GeoObjects)
            {
                if (obj.Layer.Visible)
                {
                    LineFound = obj.NearestLine(clic_object_coordinates, is_near_distance_object_coordinates);

                    if (LineFound != null)
                    {
                        return LineFound;
                    }
                }
            }

            if (LineFound == null)
            {
                LineFound = ((Archaeo.Viewport)Viewport).CurrentExcavationArea.BoundsPolyline.NearestLine(clic_object_coordinates, is_near_distance_object_coordinates);

                if (LineFound != null)
                {
                    return LineFound;
                }
            }
            return null;
        }

        /// <summary>
        /// Draw the graphics requested by the object
        /// </summary>
        public override void Draw()
        {
            if (Line1 != null)
            {
                Viewport.Graphic.DrawLine(Core.Vars.Setup.Tools.TSelection.SelectionPen,
                    Viewport.Object2ImageTransformation.Transform(Line1.Point1),
                    Viewport.Object2ImageTransformation.Transform(Line1.Point2));

                if (ShiftedLine1 != null)
                {
                    Viewport.Graphic.DrawLine(Vars.Setup.Tools.TLineDistances.ShiftedLinesPen,
                        Viewport.Object2ImageTransformation.Transform(ShiftedLine1.Point1),
                        Viewport.Object2ImageTransformation.Transform(ShiftedLine1.Point2));
                }
            }

            if (Line2 != null)
            {
                Viewport.Graphic.DrawLine(Core.Vars.Setup.Tools.TSelection.SelectionPen,
                    Viewport.Object2ImageTransformation.Transform(Line2.Point1),
                    Viewport.Object2ImageTransformation.Transform(Line2.Point2));
                if (ShiftedLine2 != null)
                {
                    Viewport.Graphic.DrawLine(Vars.Setup.Tools.TLineDistances.ShiftedLinesPen,
                        Viewport.Object2ImageTransformation.Transform(ShiftedLine2.Point1),
                        Viewport.Object2ImageTransformation.Transform(ShiftedLine2.Point2));
                }
            }
        }

        /// <summary>
        /// The method to be used to send the first message to the user, just after beeing selected
        /// </summary>
        public override void SendFirstMessage()
        {
            SendMessage("Click the first line");
        } 
        #endregion
    }
}
